Skip to content

fix: add managemement command to filter hook - #200

Open
ktyagiapphelix2u wants to merge 9 commits into
release-ulmofrom
ktyagi/filter
Open

fix: add managemement command to filter hook#200
ktyagiapphelix2u wants to merge 9 commits into
release-ulmofrom
ktyagi/filter

Conversation

@ktyagiapphelix2u

Copy link
Copy Markdown

Description

Add a pluggable filter hook in manage.py so Django management command execution can be intercepted by configured Open edX filter pipelines. This keeps edx-platform limited to the public integration point and avoids embedding org-specific monitoring logic here

Reference Ticket

https://2u-internal.atlassian.net/browse/BOMS-151

@ktyagiapphelix2u
ktyagiapphelix2u marked this pull request as ready for review July 14, 2026 13:37
Copilot AI review requested due to automatic review settings July 14, 2026 13:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an Open edX Filters integration point to manage.py so Django management command execution can be intercepted (e.g., wrapped/monitored) via configured filter pipelines, keeping org-specific logic out of edx-platform.

Changes:

  • Introduces a new public filter type (org.openedx.platform.management.command.execute.requested.v1) for management command execution.
  • Wraps execute_from_command_line in a command_runner callable and passes it through the filter pipeline before execution.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread manage.py Outdated
Comment thread manage.py Outdated
Copilot AI review requested due to automatic review settings July 20, 2026 09:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

manage.py:135

  • OpenEdxPublicFilter.run_pipeline() appears to return a tuple of the filtered values (as used elsewhere in this repo via tuple-unpacking of *.run_filter(...)). Treating the result as a dict (pipeline_output.get(...)) will raise AttributeError and cause the broad except to always fall back to command_runner, effectively preventing the filter pipeline from ever overriding the runner.
        pipeline_output = ManagementCommandExecutionRequested.run_filter(
            command_name=command_name,
            service_variant=os.environ.get("SERVICE_VARIANT", edx_args.service_variant),
            command_runner=command_runner,
        )

Comment thread manage.py Outdated
Copilot AI review requested due to automatic review settings July 23, 2026 05:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread manage.py
Comment thread manage.py Outdated
Comment thread manage.py Outdated
Comment thread manage.py Outdated
def command_runner():
return execute_from_command_line([sys.argv[0]] + django_args)

command_name = next((arg for arg in django_args if not arg.startswith('-')), 'help')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this method of calculating the command name is obscure and confusing. At least add a code comment explaining the rationale, and why the default value of "help" makes sense. Give a realistic example value of django_args and what the resulting output is supposed to be for that input value.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an explicit comment explaining how command_name is derived (first non-option token from django_args), why the fallback is help, and a concrete example input/output (for example: --verbosity 2 migrate --noinput -> migrate; --help -> help). This should make the intent clearer for future readers.

Copilot AI review requested due to automatic review settings July 28, 2026 06:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

manage.py:138

  • The current command name extraction will incorrectly pick option values as the command. For example, with django_args=['--verbosity', '2', 'migrate', '--noinput'] this code returns '2', not 'migrate', because it selects the first token that doesn't start with '-'. This will cause the filter pipeline to receive the wrong command_name for common Django global options that take values.
    # We treat the first non-option token as the Django command name.
    # Example: django_args=['--verbosity', '2', 'migrate', '--noinput'] -> 'migrate'.
    # If there is no non-option token (for example, django_args=['--help']),
    # default to 'help' because Django will print command help in that case.
    command_name = next((arg for arg in django_args if not arg.startswith('-')), 'help')

manage.py:30

  • Class name uses Contextmanager rather than the standard ContextManager CamelCase, which makes the name harder to read and inconsistent with typical Python naming for context managers.
class ManagementCommandContextmanagerRequested(OpenEdxPublicFilter):

manage.py:140

  • If the class is renamed to ManagementCommandContextManagerRequested, the call site also needs to be updated to match; otherwise this will raise a NameError at runtime.
    command_contextmanager = ManagementCommandContextmanagerRequested.run_filter(

Comment thread manage.py Outdated
Comment thread manage.py Outdated
Comment on lines +140 to +144
command_contextmanager = ManagementCommandContextmanagerRequested.run_filter(
command_contextmanager=nullcontext(),
command_name=command_name,
service_variant=os.environ.get("SERVICE_VARIANT", edx_args.service_variant),
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Output signature should match input signature:

Suggested change
command_contextmanager = ManagementCommandContextmanagerRequested.run_filter(
command_contextmanager=nullcontext(),
command_name=command_name,
service_variant=os.environ.get("SERVICE_VARIANT", edx_args.service_variant),
)
command_contextmanager, _, _ = ManagementCommandContextmanagerRequested.run_filter(
command_contextmanager=nullcontext(),
command_name=command_name,
service_variant=os.environ.get("SERVICE_VARIANT", edx_args.service_variant),
)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment thread manage.py
from openedx_filters.tooling import OpenEdxPublicFilter


class ManagementCommandContextmanagerRequested(OpenEdxPublicFilter):

@pwnage101 pwnage101 Jul 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is going to be deleted, right? It's just here temporarily to make the tests pass?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is only a temporary workaround to get the tests passing. Once openedx-filters PR is merged and released, we'll update the openedx-filters dependency in edx-platform's requirements and remove the fallback class definition from manage.py.

@pwnage101

Copy link
Copy Markdown
Member

I also just wanted to make sure you plan to add this filter call upstream to openedx/openedx-platform

Comment thread manage.py Outdated
Comment on lines +133 to +138
# django_args contains only args that argparse did not consume.
# Django treats the first positional token as the command name.
# Example: django_args=['migrate', '--noinput'] -> 'migrate'.
# If the first token is an option (for example, django_args=['--help']),
# default to 'help' so the filter sees a command-like label.
command_name = django_args[0] if django_args and not django_args[0].startswith('-') else 'help'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would --help be an illegal name for command_name? Why not just make this django_args[0], with maybe a default of no-arg-supplied if there are no arguments?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, it does feel like falling back to help can be misleading.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robrap @pwnage101 The command_name extraction in manage.py now uses django_args[0] directly, allowing option flags such as --help to be passed through unchanged instead of being mapped to help. If no arguments are provided, it defaults to no-argument.

@ktyagiapphelix2u

Copy link
Copy Markdown
Author

class ManagementCommandContextmanagerRequested(OpenEdxPublicFilter):

@pwnage101 Yes, I'm going to create an upstream PR. Once this PR is approved, I'll close it, open a new PR upstream, get that merged, and then cherry-pick the changes back into this Fork.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants